﻿using System.ComponentModel;
using System.Net;
using System.Globalization;
using System.Reflection.Metadata;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.IO;
using UMC.Net;
using UMC.Data;
using UMC.SshNet.Messages.Connection;
using UMC.ITME.Entities;

namespace UMC.ITME
{

    public class SiteConfig
    {
        public class ImageConfig
        {
            public int Width { get; set; }
            public int Height { get; set; }
            public int Postion { get; set; }
            public int ImageSize { get; set; } = 5;
            public int Model { get; set; }
            public int Padding { get; set; } = 10;
            public String Format { get; set; }
            public String Font { get; set; }
            public int FontSize { get; set; }
            public String WateRmark { get; set; }

            public String FontColor { get; set; }
            public String ImagePath { get; set; }
            public string WateRmarkText { get; set; }
        }
        public enum HeaderValueType
        {
            Unknown,
            ACCOUNT,
            ROLES,
            TOKEN,
            USERID,
            USERNAME, HOST, SCHEME, ADDRESS, PREHOST
        }
        public class HeaderConfItem
        {
            public StringValue Name { get; set; }
            public StringValue Prefix { get; set; }
            public StringValue Value { get; set; }
            public HeaderValueType Type { get; set; }
        }
        class UMCUri : Uri
        {
            public UMCUri([StringSyntax("Uri")] string uriString) : base(uriString)
            {
                isPort = uriString.IndexOf(":", 7) > -1;
            }
            bool isPort;
            public string UMCAuthority
            {
                get
                {
                    if (isPort)
                    {
                        return $"{this.Host}:{this.Port}";

                    }
                    else
                    {
                        return this.Authority;
                    }
                }

            }
        }
        public enum HostReplaceModel
        {
            None = 0,
            Replace = 1,
            Input = 4,
            // CDN = 8,
            // Script = 16
        }
        public class Block
        {
            public String Value
            {
                get;
                set;
            }
            public BlockType Type
            {
                get; set;
            }
            public string Content
            {
                get; set;
            }
        }
        public enum BlockType
        {
            Nodejs = 0,
            Login = 1,
            Redirect = 2,
            Url = 3
        }
        public String GetHome()
        {
            if (this.Home.EndsWith("_t="))
            {

                return $"{this.Home}{Utility.TimeSpan()}";
            }
            else
            {
                return this.Home;

            }
        }
        public class ReplaceSetting
        {
            public HostReplaceModel Model
            {
                get;
                set;
            }

            Set<HostConvert> _Domains = new Set<HostConvert>(Comparer<HostConvert>.Create((x, y) => x.Hosts[0].AsSpan().SequenceCompareTo(y.Hosts[0].AsSpan())));
            public Set<HostConvert> Domains
            {
                get
                {
                    return _Domains;
                }
            }
        }
        public class LogSetting
        {
            public String[] Cookies
            {
                get;
                set;
            }
            public String[] Headers
            {
                get;
                set;
            }
            public string[] ResHeaders
            {
                get;
                set;
            }
        }
        public class TestUrl
        {
            public String[] Users
            {
                get;
                set;
            }
            public StringValue[] Auths
            {
                get;
                set;
            }
            public string Url
            {

                get;
                set;
            }
        }
        public class HostConvert
        {
            public byte[][] Hosts = new byte[4][];
            public byte[][] Hex = new byte[4][];
        }
        public class KeyValue
        {

            public StringValue Key
            {

                get;
                set;
            }
            public string Value
            {

                get;
                set;
            }
            public bool IsDel
            {
                get; set;
            }
        }

        public int WeightTotal
        {
            get;
            private set;
        }
        public int[] Weights
        {
            get;
            private set;
        }
        public string Caption
        {
            get; private set;
        }
        public bool IsFile
        {

            get; private set;
        }
        public bool IsDisabledFingerprint
        {
            get; private set;
        }
        public SiteConfig() { }
        public bool IsGotoMain
        {

            get; private set;
        }
        public bool AllowRootDomain
        {
            get; private set;
        }
        public int ApiSecureBodyTimeOut
        {
            get; private set;
        } = 300;

        public int ApiSecureHeadTimeOut
        {
            get; private set;
        } = 10;

        public int ApiSecureTime
        {
            get; private set;
        } = 60;
        public int ApiSecureNetworkSpeed
        {
            get; private set;
        } = 100;
        public int ApiSecureFieldSize
        {
            get; private set;
        } = 500;
        public int ApiSecureUrlSize
        {
            get; private set;
        } = 1500;

        public int ApiSecureHeadSize
        {
            get; private set;
        } = 30;
        public int ApiSecureHeadCount
        {
            get; private set;
        } = 30;
        public int ApiSecureConnections
        {
            get; private set;
        } = 100;
        public int ApiSecureBodySize
        {
            get; private set;
        }
        public int ApiSecureLockTimes
        {
            get; private set;
        } = 5;

        public StringValue AppId
        {
            get; private set;
        }
        public Socks5 Proxy
        {
            get; private set;
        }
        public StringValue AppSecret
        {
            get; private set;
        } = StringValue.Empty;

        public bool IsForwardProxy
        {
            get; private set;
        }
        public int ApiSecureRepetitions
        {
            get; private set;
        } = 15;
        public SiteConfig(Entities.Site site)
        {
            this.Caption = site.Caption;

            if (String.IsNullOrEmpty(site.AppSecret) == false)
            {
                var appId = WebResource.Instance().Provider["appSecret"];
                if (String.IsNullOrEmpty(appId) == false)
                {
                    this.AppSecret = new StringValue(Utility.Guid(site.AppSecret).Value.ToByteArray());
                }
            }
            this.AppId = new StringValue(Utility.MD5(site.Root.UTF8()));

            if (String.IsNullOrEmpty(site.Home) == false)
            {
                IsGotoMain = site.Home.EndsWith("#");
                if (IsGotoMain)
                {
                    this.Home = site.Home.Substring(0, site.Home.Length - 1);
                }
                else
                {

                    this.Home = site.Home;
                }
            }
            else
            {
                this.Home = "/";
            }

            this.Root = site.Root;

            this.Site = site;
            this.IsDisabledFingerprint = (site.Type & 1024) > 0;
            this.IsForwardProxy = (site.Type & 2048) > 0;
            this.ApiSecureRepetitions = site.ApiSecureRepetitions ?? 30;
            this.ApiSecureTime = site.ApiSecureTime ?? 60;
            this.ApiSecureLockTimes = site.ApiSecureLockTimes ?? 5;
            this.ApiSecureNetworkSpeed = site.ApiSecureNetworkSpeed ?? 100;
            this.ApiSecureHeadCount = site.ApiSecureHeadCount ?? 30;
            this.ApiSecureFieldSize = site.ApiSecureFieldSize ?? 500;
            this.ApiSecureBodyTimeOut = site.ApiSecureBodyTimeOut ?? 300;
            this.ApiSecureHeadTimeOut = site.ApiSecureHeadTimeOut ?? 10;
            this.ApiSecureConnections = site.ApiSecureConnections ?? 100;

            if (String.IsNullOrEmpty(site.ApiSecureBodySize) == false)
            {
                var bsize = site.ApiSecureBodySize.ToLower().Trim('b');
                if (bsize.EndsWith("k"))
                {
                    this.ApiSecureBodySize = Utility.IntParse(bsize.Substring(0, bsize.Length - 1), 0) * 1024;
                }
                else if (bsize.EndsWith("m"))
                {

                    this.ApiSecureBodySize = Utility.IntParse(bsize.Substring(0, bsize.Length - 1), 0) * 1024 * 1024;

                }
                else if (bsize.EndsWith("g"))
                {
                    this.ApiSecureBodySize = Utility.IntParse(bsize.Substring(0, bsize.Length - 1), 0) * 1024 * 1024 * 1024;
                }
                else
                {
                    this.ApiSecureBodySize = Utility.IntParse(bsize.Substring(0, bsize.Length - 1), 0);
                }
            }
            // Utility.GetBitSize()
            this.IsDisabledApiSecure = (site.Type & 8) > 0;
            this.PrefixHost = new Set<StringValue, string>((x, y) => x.Span.SequenceCompareTo(y.Span));
            this.ReferenceHost = new Set<StringValue, Uri>((x, y) => x.Span.SequenceCompareTo(y.Span));

            var dom = site.Domain.Split(',', '\n');
            List<string> domains = new List<string>();
            var ls = new List<int>();
            var total = 0;
            var test = new Dictionary<String, TestUrl>();
            for (var i = 0; i < dom.Length; i++)
            {
                var v = dom[i].Trim();
                int end = v.IndexOf('#');
                if (end > -1)
                {
                    v = v.Substring(0, end).Trim();
                }
                if (String.IsNullOrEmpty(v) == false)
                {
                    var valueIndex = v.IndexOf('~');
                    if (valueIndex > 0)
                    {
                        var KeepAlive = v.Substring(valueIndex + 1).Trim();
                        v = v.Substring(0, valueIndex).Trim();

                        var tIndex = v.LastIndexOf("/");
                        try
                        {
                            var kUrl = new Uri(tIndex > 8 ? v.Substring(0, tIndex) : v);
                            switch (KeepAlive)
                            {
                                // case "dns":
                                //     Net.NetProxy.DNS(kUrl.Host, NetProxy.DNSType.DNS);
                                //     break;
                                // case "dns4":
                                //     Net.NetProxy.DNS(kUrl.Host, NetProxy.DNSType.IP4 | NetProxy.DNSType.DNS);
                                //     break;
                                // case "dns6":
                                //     Net.NetProxy.DNS(kUrl.Host, NetProxy.DNSType.IP6 | NetProxy.DNSType.DNS);
                                //     break;
                                // case "ip4":
                                //     Net.NetProxy.DNS(kUrl.Host, NetProxy.DNSType.IP4);
                                //     break;
                                // case "ip6":
                                //     Net.NetProxy.DNS(kUrl.Host, NetProxy.DNSType.IP6);
                                //     break;
                                default:
                                    if (KeepAlive.StartsWith("q"))
                                    {
                                        Net.NetProxy.QPS(kUrl, Utility.IntParse(KeepAlive.Substring(1), 0));
                                    }
                                    else
                                    {
                                        Net.NetProxy.KeepAlives(kUrl, Utility.IntParse(KeepAlive, 60));
                                    }
                                    break;
                            }
                        }
                        catch
                        {
                            continue;
                        }
                    }
                    if (v.StartsWith("dns://"))
                    {
                        continue;
                    }
                    else if (v.StartsWith("socks5://"))
                    {
                        this.Proxy = Utility.GetSocks5(v);
                        continue;
                    }
                    else if (v.StartsWith("http://") || v.StartsWith("https://") || v.StartsWith("file://") || v.StartsWith("unix://"))
                    {
                        if (v.EndsWith("]"))
                        {
                            var tUrl = v;

                            var vin = v.LastIndexOf("[");
                            if (vin > -1)
                            {
                                ls.Add(UMC.Data.Utility.IntParse(v.Substring(vin + 1).Trim(']', '[').Trim(), 1));

                                total += ls[ls.Count - 1];
                                tUrl = v.Substring(0, vin).TrimEnd(']', ' ').Trim();
                            }
                            else
                            {
                                total++;
                                ls.Add(1);
                            }

                            var sIndex = tUrl.IndexOf('/', 8);
                            if (sIndex > 0)
                            {
                                tUrl = tUrl.Substring(0, sIndex);
                            }
                            domains.Add(tUrl);

                        }
                        else
                        {
                            var tIndex = v.IndexOf('@');
                            var tUrl = v;
                            if (tIndex > 0)
                            {
                                tUrl = v.Substring(0, tIndex);
                                var uvs = v.Substring(tIndex + 1).Split(',', ' ');
                                var tUsers = new List<String>();
                                var tAuth = new List<StringValue>();
                                foreach (var uv in uvs)
                                {
                                    var uname = uv.Trim();
                                    if (String.IsNullOrEmpty(uname) == false)
                                    {
                                        if (uname.IndexOf('/') == -1)
                                        {
                                            tUsers.Add(uname);
                                        }
                                        else
                                        {
                                            tAuth.Add(new StringValue(uname));
                                        }
                                    }
                                }
                                if (tUsers.Count > 0 || tAuth.Count > 0)
                                {
                                    var sIndex = tUrl.IndexOf('/', 8);//, tIndex);
                                    if (sIndex > 0)
                                    {
                                        tUrl = tUrl.Substring(0, sIndex);
                                    }

                                    test[tUrl.Trim()] = new TestUrl { Auths = tAuth.ToArray(), Users = tUsers.ToArray(), Url = tUrl };
                                }
                            }
                            else
                            {
                                if (tUrl.StartsWith("file://") == false)
                                {
                                    if (tUrl.EndsWith("/$"))
                                    {
                                        this.AllowRootDomain = true;
                                    }
                                    var sIndex = tUrl.IndexOf('/', 8);
                                    if (sIndex > 0)
                                    {
                                        tUrl = tUrl.Substring(0, sIndex);
                                    }
                                }
                                domains.Add(tUrl);
                                total++;
                                ls.Add(1);
                            }

                        }
                    }
                    else if (v.Contains('.'))
                    {
                        var sp = v.IndexOfAny(new char[] { ':', ' ' });
                        if (sp > 0)
                        {
                            var value = v.Substring(sp + 1);
                            if (value.StartsWith("https://") || value.StartsWith("http://"))
                            {
                                try
                                {
                                    this.ReferenceHost[new StringValue(v.Substring(0, sp).Trim())] = new Uri(new Uri(value), "/");// v.Substring(sp + 1).Trim();
                                }
                                catch
                                {

                                }
                            }
                            else if (System.Text.RegularExpressions.Regex.IsMatch(value, @"^([a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?\.)+[a-z0-9]{1,6}$"))
                            {
                                if (domains.Exists(r => r.StartsWith("https://")))
                                {
                                    this.ReferenceHost[new StringValue(v.Substring(0, sp).Trim())] = new Uri(new Uri($"https://{value}"), "/");
                                }
                                else if (domains.Exists(r => r.StartsWith("http://")))
                                {
                                    this.ReferenceHost[new StringValue(v.Substring(0, sp).Trim())] = new Uri(new Uri($"http://{value}"), "/");
                                }
                            }
                        }
                        else
                        {
                            this.PrefixHost[new StringValue(v.Replace('.', '-'))] = v;
                        }
                    }
                }

                if (domains.Count > 0)
                {
                    if (IsFile == false)
                    {
                        var url = domains.Last();
                        IsFile = url.StartsWith("file://", StringComparison.CurrentCultureIgnoreCase);
                        if (IsFile)
                        {
                            domains.Clear();
                            domains.Add(url);
                            break;
                        }
                    }
                }
            }
            this.Domains = domains.ToArray();
            this._test = test.Values.ToArray();

            this.WeightTotal = total;
            this.Weights = ls.ToArray();
            initLoginPath();
            this.AppendJSConf = ConfigValue(site.AppendJSConf);
            this.RedirectPath = ConfigValue(site.RedirectPath);
            // this.ImagesConf = ConfigValue(site.ImagesConf);
            InitConfigImages(site.ImagesConf);
            this.ConfigAllowPath(site.AuthConf);
            var subSite = new List<KeyValue>();
            if (String.IsNullOrEmpty(site.SubSite) == false)
            {
                var v = UMC.Data.JSON.Deserialize(site.SubSite) as Hashtable;
                if (v != null)
                {
                    var pem = v.GetEnumerator();
                    while (pem.MoveNext())
                    {
                        var key = pem.Key as string;
                        if (key.EndsWith("*"))
                        {
                            subSite.Add(new KeyValue { Key = new StringValue(key.Substring(0, key.Length - 1).UTF8()), Value = pem.Value.ToString(), IsDel = true });
                        }
                        else
                        {
                            subSite.Add(new KeyValue { Key = new StringValue(key.UTF8()), Value = pem.Value.ToString() });
                        }

                    }
                }
            }
            _subSite = subSite.ToArray();
            InitStatic(site.StaticConf);
            InitHeader(site.HeaderConf);
            InitLogConf(site.LogConf);

            InitCookie(site.OutputCookies);

            InitHost(site.HostReConf);
            InitRES_Block();
            InitHighFrequency();
            MimeInit();
            if (this.IsForwardProxy && this.IsUnion)
            {

                var proxySites = HotCache.Find(new ProxySite());
                var siteKey = site.SiteKey.Value.StringValue();
                if (proxySites.Any(r => r.ConfigKey.Contains(siteKey.Span)) == false)
                {

                    var d = this.Domains[0];
                    var dIndex = d.IndexOf('*');


                    var host = new StringValue(d.Substring(dIndex + 2));


                    var proxySite = proxySites.FirstOrDefault(r => r.Domain.Span.SequenceEqual(host.Span));// HotCache.Get(new ProxySite { Domain = host });
                    var KeyValue = this.Site.SiteKey.Value.StringValue().Span;
                    if (proxySite == null || proxySite.ConfigKey?.Contains(KeyValue) != true)
                    {
                        var l = proxySite?.ConfigKey?.Length ?? 0;
                        if (l == 0)
                        {
                            HotCache.Put(new ProxySite { Domain = host, ConfigKey = new StringValue(KeyValue.ToArray()) });
                        }
                        else
                        {
                            var configValue = new byte[l + 4];
                            proxySite.ConfigKey.Span.CopyTo(configValue);
                            KeyValue.CopyTo(configValue.AsSpan(l));
                            HotCache.Put(new ProxySite { Domain = host, ConfigKey = new StringValue(configValue) });
                        }

                        Utility.SyncClient(3, host, 0.StringValue());
                    }
                }


            }

            IsCheck();
        }
        public bool RemoveWeight(String authority)
        {
            var ds = this.Domains;
            if (ds.Length > 1)
            {
                for (var i = 0; i < ds.Length; i++)
                {
                    if (ds[i].Contains(authority))
                    {
                        var ls = ds.ToList();
                        ls.RemoveAt(i);
                        var ws = this.Weights.ToList();
                        ws.RemoveAt(i);
                        this.WeightTotal -= ws[i];
                        this.Weights = ws.ToArray();
                        this.Domains = ls.ToArray();
                        return true;
                    }
                }
            }
            return false;
        }
        void initLoginPath()
        {
            var sConf = this.Site.LogoutPath;
            if (String.IsNullOrEmpty(sConf) == false)
            {

                foreach (var k in sConf.Split('\n'))
                {
                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {

                        var vin = v.IndexOfAny(new char[] { ':', ' ', '\t' });
                        var key = v;//String.Empty;
                        var value = String.Empty;
                        if (vin > 0)
                        {
                            key = v.Substring(0, vin);
                            value = v.Substring(vin + 1).Trim();
                        }
                        else if (v.StartsWith('@'))
                        {
                            key = v.Substring(1);
                            value = "@";
                        }
                        switch (key[key.Length - 1])
                        {
                            case '$':
                                this._LogoutPath.Put(Tuple.Create(new StringValue(key.Substring(0, key.Length - 1).UTF8()), value, 2));
                                break;
                            case '*':
                                this._LogoutPath.Put(Tuple.Create(new StringValue(key.Substring(0, key.Length - 1).UTF8()), value, 1));
                                // this._LogoutPath[new StringValue(key.Substring(0, key.Length - 1).UTF8())] = Tuple.Create(value, 1);
                                break;
                            default:
                                this._LogoutPath.Put(Tuple.Create(new StringValue(key.Substring(0, key.Length - 1).UTF8()), value, 0));
                                // this._LogoutPath[new StringValue(key.UTF8())] = Tuple.Create(value, 0);
                                break;
                        }

                    }
                }
            }
        }
        public bool AllowAllPath
        {
            get; set;
        }

        /// <summary>
        /// 默认ContentType类型
        /// </summary>
        public StringValue ContentType
        {
            get; set;
        } = StringValue.Empty;
        public static bool CheckMime(MimeFeildConfig login)
        {
            if (String.IsNullOrEmpty(login.RawUrl))
            {
                return false;

            }
            if (login.Method == HttpMethod.None)
            {
                return false;
            }
            switch (login.Method)
            {
                case HttpMethod.POST:
                case HttpMethod.PUT:
                    if (login.ContentType.IsEmpty)
                    {
                        return false;
                    }
                    if (String.IsNullOrEmpty(login.Content))
                    {
                        return false;
                    }
                    break;
            }
            if (login.Finish.IsEmpty)
            {
                return false;
            }
            return true;
        }
        public static bool CheckMime(Hashtable login)
        {
            var rawUrl = login["RawUrl"] as string;
            if (String.IsNullOrEmpty(rawUrl))
            {
                return false;

            }


            var Method = login["Method"] as string;
            if (String.IsNullOrEmpty(Method))
            {
                return false;
            }

            switch (Method)
            {
                case "POST":
                case "PUT":
                    var ContentType = login["ContentType"] as string;
                    if (String.IsNullOrEmpty(ContentType))
                    {
                        return false;
                    }
                    var value = login["Content"] as string;
                    if (String.IsNullOrEmpty(value))
                    {
                        return false;
                    }
                    break;
            }
            var Finish = login["Finish"] as string;
            if (String.IsNullOrEmpty(Finish))
            {
                return false;
            }
            return true;
        }
        void InitLogConf(String sConf)
        {

            this.LogConf = new LogSetting();

            var cs = new List<String>();
            var hs = new List<String>();
            var rhs = new List<String>();
            if (String.IsNullOrEmpty(sConf) == false)
            {
                foreach (var k in sConf.Split('\n', ','))
                {

                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {
                        if (v.StartsWith(":"))
                        {
                            hs.Add(v.Substring(1));
                        }
                        else if (v.EndsWith(":"))
                        {

                            rhs.Add(v.Substring(0, v.Length - 1));
                        }
                        else
                        {
                            cs.Add(v);
                        }
                    }

                }
            }

            this.LogConf.Headers = hs.ToArray();
            this.LogConf.ResHeaders = rhs.ToArray();
            this.LogConf.Cookies = cs.ToArray();
        }
        public int CheckTime
        {
            get; private set;
        }
        public bool IsOutputAllCookies
        {

            get; private set;
        }
        void InitCookie(String sConf)
        {
            if (String.IsNullOrEmpty(sConf) == false)
            {

                foreach (var k in sConf.Split('\n'))
                {
                    var end = k.IndexOf('#');

                    var v = end > 0 ? k.Substring(0, end).Trim() : k.Trim();
                    String pfx = String.Empty;
                    end = v.IndexOf('@');
                    if (end > 0)
                    {
                        pfx = v.Substring(end + 1).Trim();
                        v = v.Substring(0, end).Trim();
                    }

                    if (String.IsNullOrEmpty(v) == false)
                    {
                        var key = v;

                        CookieSet.Cookie cookie = new CookieSet.Cookie();

                        cookie.Path = new StringValue("/");
                        int pIndex = key.IndexOf('/');
                        if (pIndex > 0)
                        {
                            cookie.Name = new StringValue(key.Substring(0, pIndex).Trim());
                            cookie.Path = new StringValue(key.Substring(pIndex).Trim());
                        }
                        else
                        {
                            cookie.Name = new StringValue(key);
                        }
                        if (String.IsNullOrEmpty(pfx) == false)
                        {
                            cookie.Domain = new StringValue(pfx);
                        }

                        if (cookie.Name.Span.SequenceEqual("*"u8) == false)
                        {
                            _OutputCookies.Put(cookie);

                        }
                        else
                        {
                            this.IsOutputAllCookies = true;
                        }

                    }

                }
            }
            // this._HiddentCookies = strings.ToArray();

            //    this
        }
        Hashtable GetConf(String mainKey)
        {
            var login = new Hashtable();
            var pconfig = UMC.Data.DataFactory.Instance().Config(mainKey)?.ConfValue?.UTF8();

            var v = UMC.Data.JSON.Deserialize(pconfig) as Hashtable;
            if (v != null)
            {
                login = v;
            }
            return login;
        }
        void InitHeader(String sConf)
        {

            // this.goto
            if (String.IsNullOrEmpty(sConf) == false)
            {

                foreach (var k in sConf.Split('\n'))
                {

                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {

                        var nindex = v.IndexOfAny(new char[] { ' ', '\t', ':' });

                        if (nindex > -1)
                        {
                            var mv = v.Substring(nindex + 1).Trim();
                            var key = v.Substring(0, nindex).Trim();
                            if (String.IsNullOrEmpty(mv) == false && String.IsNullOrEmpty(key) == false)
                            {
                                switch (key.ToLower())
                                {
                                    case "content-type":
                                        this.ContentType = new StringValue(mv.UTF8());
                                        break;
                                    default:
                                        var m = mv.LastIndexOf('@');
                                        var val = mv;
                                        var item = new HeaderConfItem() { Name = new StringValue(key), Prefix = StringValue.Empty };
                                        if (m > -1)
                                        {
                                            val = mv.Substring(0, m);
                                            item.Value = new StringValue(val);
                                            item.Prefix = new StringValue(mv.Substring(m + 1));
                                        }
                                        else
                                        {
                                            item.Value = new StringValue(val);
                                        }
                                        item.Type = ToHeaderValueType(val);

                                        _HeaderConf.Put(item);
                                        break;
                                }
                            }

                        }
                        else
                        {
                            nindex = v.IndexOf('=');// -1;
                            if (nindex > 0)
                            {
                                var mv = v.Substring(nindex + 1).Trim();
                                var m = mv.LastIndexOf('@');
                                var val = mv;
                                var item = new HeaderConfItem() { Name = new StringValue(v.Substring(0, nindex).Trim()), Prefix = StringValue.Empty };
                                if (m > -1)
                                {
                                    val = mv.Substring(0, m);
                                    item.Value = new StringValue(val);
                                    item.Prefix = new StringValue(mv.Substring(m + 1));
                                }
                                else
                                {
                                    item.Value = new StringValue(val);
                                }
                                item.Type = ToHeaderValueType(val);

                                _AppendCookies.Put(item);
                            }
                        }
                    }

                }

            }
        }
        public static HeaderValueType ToHeaderValueType(String val)
        {
            switch (val)
            {
                case "ACCOUNT":
                    return HeaderValueType.ACCOUNT;

                case "ROLES":
                    return HeaderValueType.ROLES;

                case "TOKEN":
                    return HeaderValueType.TOKEN;

                case "USERID":
                    return HeaderValueType.USERID;

                case "USERNAME":
                    return HeaderValueType.USERNAME;

                case "HOST":
                    return HeaderValueType.HOST;

                case "SCHEME":
                    return HeaderValueType.SCHEME;

                case "ADDRESS":
                    return HeaderValueType.ADDRESS;

                case "PREHOST":
                    return HeaderValueType.PREHOST;
                default:
                    return HeaderValueType.Unknown;
            }
        }
        void InitStatic(String sConf)
        {
            var stateValues = new List<PageConfig<int>>();
            if (String.IsNullOrEmpty(sConf) == false)
            {
                foreach (var k in sConf.Split('\n', ','))
                {

                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {

                        var nindex = -1;
                        for (int i = 0; i < v.Length; i++)
                        {
                            if (v[i] == ' ' || v[i] == '\t' || v[i] == ':')
                            {
                                nindex = i;
                                break;
                            }
                        }
                        var page = new PageConfig<int>() { StartPath = StringValue.Empty, EndPath = StringValue.Empty };
                        page.Value = -1;
                        var key = v;
                        if (nindex > -1)
                        {
                            var mv = v.Substring(nindex + 1).Trim().ToLower();
                            key = v.Substring(0, nindex).Trim();
                            var splitIndex = key.IndexOf('*');
                            switch (splitIndex)
                            {
                                case -1:
                                    page.StartPath = new StringValue(key);
                                    break;
                                case 0:
                                    if (key.Length > 1)
                                    {
                                        page.EndPath = new StringValue(key.Substring(1));
                                    }
                                    else
                                    {
                                        continue;
                                    }

                                    break;
                                default:
                                    if (splitIndex == key.Length - 1)
                                    {
                                        page.StartPath = new StringValue(key.Substring(0, key.Length - 1));
                                    }
                                    else
                                    {
                                        page.StartPath = new StringValue(key.Substring(0, splitIndex));
                                        page.EndPath = new StringValue(key.Substring(splitIndex + 1));

                                    }

                                    break;

                            }
                            switch (mv)
                            {
                                case "a":
                                case "all":
                                    page.Value = 0;
                                    break;
                                case "u":
                                case "user":
                                    page.Value = 2;
                                    break;
                                case "one":
                                    page.Value = 3;
                                    break;
                                default:
                                    page.Value = UMC.Data.Utility.IntParse(mv, -1);
                                    break;
                            }
                        }
                        else
                        {
                            page.StartPath = new StringValue(key);
                        }
                        stateValues.Add(page);
                    }

                }

            }
            _StatusPage = stateValues.ToArray();
        }
        public HostConvert MainHost
        {
            get;
            private set;
        }
        public bool IsUnion
        {
            get;
            private set;
        }

        public HostConvert SuffixHost
        {
            get;
            private set;
        }
        public Set<StringValue, String> PrefixHost
        {
            get; private set;
        }
        public Set<StringValue, Uri> ReferenceHost
        {
            get; private set;
        }
        HostConvert ReferenceHosts(String key, Uri value)
        {

            var vkb = System.Text.ASCIIEncoding.UTF8.GetBytes(key);
            var vhm = new byte[vkb.Length + this.MainHost.Hosts[0].Length];
            Array.Copy(vkb, 0, vhm, 0, vkb.Length);
            Array.Copy(this.MainHost.Hosts[0], 0, vhm, vkb.Length, this.MainHost.Hosts[0].Length);
            var hostConvert = new HostConvert();
            hostConvert.Hosts[0] = vhm;

            hostConvert.Hosts[1] = System.Text.ASCIIEncoding.UTF8.GetBytes(value.Host);
            hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes(value.Authority);
            hostConvert.Hosts[3] = System.Text.ASCIIEncoding.UTF8.GetBytes(Uri.EscapeDataString(value.Authority));

            Hex(hostConvert);
            return hostConvert;
        }
        HostConvert Convert(String key, String value)
        {
            var vkb = System.Text.ASCIIEncoding.UTF8.GetBytes(key);
            var vhm = new byte[vkb.Length + this.MainHost.Hosts[0].Length];
            Array.Copy(vkb, 0, vhm, 0, vkb.Length);
            Array.Copy(this.MainHost.Hosts[0], 0, vhm, vkb.Length, this.MainHost.Hosts[0].Length);
            var hostConvert = new HostConvert();
            hostConvert.Hosts[0] = vhm;

            var vsrcb = System.Text.ASCIIEncoding.UTF8.GetBytes(value);
            for (var i = 1; i <= 3; i++)
            {
                var vhm1 = new byte[vkb.Length + this.MainHost.Hosts[i].Length];

                Array.Copy(vsrcb, 0, vhm1, 0, vsrcb.Length);

                Array.Copy(this.MainHost.Hosts[i], 0, vhm1, vsrcb.Length, this.MainHost.Hosts[i].Length);

                hostConvert.Hosts[i] = vhm1;
            }
            Hex(hostConvert);
            return hostConvert;
        }
        StringValue GetValue(string v)
        {
            if (String.IsNullOrEmpty(v) == false)
            {
                return new StringValue(v);
            }
            else
            {
                return StringValue.Empty;
            }
        }
        void SetMimeConfig(MimeConfig mimeConfig, Hashtable hashtable)
        {
            var Domain = hashtable["Domain"] as string;
            if (String.IsNullOrEmpty(Domain) == false)
            {
                try
                {
                    mimeConfig.Domain = new Uri(Domain);
                }
                catch
                {

                }
            }
            mimeConfig.Content = hashtable["Domain"] as string;
            mimeConfig.Content = hashtable["Content"] as string;

            mimeConfig.Finish = GetValue(hashtable["Finish"] as string);
            mimeConfig.ContentType = GetValue(hashtable["ContentType"] as string);

            switch (hashtable["Method"] as string)
            {
                case "PUT":
                    mimeConfig.Method = HttpMethod.PUT;
                    break;
                case "POST":
                    mimeConfig.Method = HttpMethod.POST;
                    break;
                default:
                    mimeConfig.Method = HttpMethod.GET;
                    break;
            }
            // mimeConfig.Method = new StringValue((hashtable["Method"] as string) ?? String.Empty);
            mimeConfig.DefautValue = hashtable["DefautValue"] as string;
            mimeConfig.Script = hashtable["Script"] as string;
            mimeConfig.RawUrl = hashtable["RawUrl"] as string;
            mimeConfig.IsRememberValue = hashtable.ContainsKey("RememberValue");//["RawUrl"];

            mimeConfig.RetryCount = Utility.IntParse(hashtable["RetryCount"] as string, 0);
            var header = hashtable["Header"] as string;
            if (String.IsNullOrEmpty(header) == false)
            {
                var hs = header.Split('\n');
                foreach (var h in hs)
                {
                    var hi = h.IndexOf(":");
                    if (hi > 0)
                    {
                        var key = h.Substring(0, hi).Trim();
                        var value = h.Substring(hi + 1).Trim();
                        if (String.IsNullOrEmpty(key) == false && String.IsNullOrEmpty(value) == false)
                        {
                            var item = new SiteConfig.HeaderConfItem() { Name = new StringValue(key), Prefix = StringValue.Empty, Value = new StringValue(value) };
                            item.Type = ToHeaderValueType(value);// Utility.Parse(value, HeaderValueType.Unknown);
                            mimeConfig.Headers.Put(item);
                            // mimeConfig.Headers.Add(new StringValue(key), value);
                        }
                    }
                }

            }
        }
        List<MimeConfig> GetFeilds(Hashtable hashtable, string type)
        {
            var ls = new List<MimeConfig>();
            var feilds = hashtable["Feilds"] as Hashtable ?? new Hashtable();
            if (feilds.Count > 0)
            {
                var fd = feilds.Keys.Cast<String>().OrderBy(r => r).GetEnumerator();
                while (fd.MoveNext())
                {
                    var fdKey = fd.Current;

                    var conf = GetConf($"SITE_MIME_{Site.Root}_{type}_{fdKey}".ToUpper());
                    var mime3 = new MimeConfig();
                    mime3.Name = fdKey;
                    mime3.Caption = feilds[fdKey] as string;
                    this.SetMimeConfig(mime3, conf);


                    ls.Add(mime3);

                }
                ls.Sort(Comparer<MimeConfig>.Create((x, y) => x.Name.CompareTo(y.Name)));
            }
            return ls;
        }
        public LoginConfig Login
        {
            get; set;
        }

        public UpdateConfig Update
        {
            get; set;
        }

        public CheckConfig Check
        {
            get; set;
        }
        void MimeInit()
        {

            var login = GetConf(String.Format("SITE_MIME_{0}_LOGIN", Site.Root).ToUpper());
            var miLogin = new LoginConfig();
            this.SetMimeConfig(miLogin, login);
            // miLogin.Callback = 
            var cl = login["Callback"] as string;
            if (String.IsNullOrEmpty(cl) == false)
            {
                miLogin.Callback = cl;// new StringValue(cl);
            }
            else
            {
                miLogin.Callback = "callback";
            }
            miLogin.IsLoginHTML = login.ContainsKey("IsLoginHTML");
            miLogin.IsNotCookieClear = login.ContainsKey("IsNotCookieClear");
            var fes = this.GetFeilds(login, "LOGIN");
            miLogin.LoginAfter = fes.FirstOrDefault(r => String.Equals(r.Name, "LoginAfter", StringComparison.CurrentCultureIgnoreCase));

            if (miLogin.LoginAfter != null)
            {
                fes.Remove(miLogin.LoginAfter);
            }

            miLogin.Feilds = fes.ToArray();

            this.Login = miLogin;

            this.Update = new UpdateConfig();
            var update = GetConf(String.Format("SITE_MIME_{0}_UPDATE", Site.Root).ToUpper());

            this.SetMimeConfig(Update, update);
            this.Update.Feilds = this.GetFeilds(update, "UPDATE").ToArray();

            this.Update.UpdateModel = update["UpdateModel"] as string;

            this.Check = new CheckConfig();
            var check = GetConf(String.Format("SITE_MIME_{0}_CHECK", Site.Root).ToUpper());
            this.SetMimeConfig(Update, check);

            this.Check.Feilds = this.GetFeilds(check, "CHECK").ToArray();

            this.Check.IsNotLoginApi = check.ContainsKey("IsNotLoginApi");//["UpdateModel"] as string;




        }
        public Set<PageConfig<int>> HighFrequency
        {
            get;
            private set;
        }
        void InitHighFrequency()
        {
            var configKey = $"SITE_HIGHFREQUENCY_{this.Site.Root}".ToUpper();
            var sConf = (UMC.Data.DataFactory.Instance().Config(configKey)?.ConfValue ?? StringValue.Empty).UTF8();


            var saticPagePath = new Set<PageConfig<int>>(PageConfig<int>.comparer);
            if (String.IsNullOrEmpty(sConf) == false)
            {

                foreach (var k in sConf.Split('\n'))
                {
                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {
                        if (String.IsNullOrEmpty(v))
                        {
                            continue;
                        }
                        var page = new PageConfig<int>() { StartPath = StringValue.Empty, EndPath = StringValue.Empty };

                        var splitIndex = v.IndexOf('*');
                        switch (splitIndex)
                        {
                            case -1:
                                page.StartPath = new StringValue(v);
                                break;
                            case 0:
                                if (v.Length > 1)
                                {
                                    page.EndPath = new StringValue(v.Substring(1));
                                }
                                else
                                {
                                    continue;
                                }

                                break;
                            default:
                                if (splitIndex == v.Length - 1)
                                {
                                    page.StartPath = new StringValue(v.Substring(0, v.Length - 1));
                                }
                                else
                                {
                                    page.StartPath = new StringValue(v.Substring(0, splitIndex));
                                    page.EndPath = new StringValue(v.Substring(splitIndex + 1));

                                }

                                break;

                        }
                        saticPagePath.Put(page);


                    }

                }
            }
            this.HighFrequency = saticPagePath;
        }

        void InitRES_Block()
        {

            var configKey = $"SITE_RES_BLOCK_{this.Site.Root}".ToUpper();
            var sConf = (UMC.Data.DataFactory.Instance().Config(configKey)?.ConfValue ?? StringValue.Empty).UTF8();
            // var sConf = UMC.Data.DataFactory.Instance().Config(configKey)?.ConfValue ?? Array.Empty<byte>();
            if (String.IsNullOrEmpty(sConf) == false)
            {
                foreach (var k in sConf.Split('\n'))
                {
                    var end = k.IndexOf('#');

                    var v = end > 0 ? k.Substring(0, end).Trim() : k.Trim();

                    if (String.IsNullOrEmpty(v) == false)
                    {
                        var nindex = v.IndexOfAny(new char[] { ' ', '\t' });// - 1;// v.Length - 1;
                        if (nindex > 0)
                        {
                            var path = v.Substring(0, nindex).Trim();
                            if (path.StartsWith("/"))
                            {
                                var file = v.Substring(nindex + 1).Trim();

                                if (file.StartsWith("http://") || file.StartsWith("https://"))
                                {
                                    var vfIndex = file.IndexOfAny(new char[] { ' ', '\t' });
                                    if (vfIndex > 0)
                                    {
                                        _ResBlockPage[new StringValue(path)] = new Block { Value = file.Substring(0, vfIndex), Content = file.Substring(vfIndex + 1).Trim(), Type = BlockType.Redirect };
                                    }
                                    else
                                    {
                                        _ResBlockPage[new StringValue(path)] = new Block { Value = file, Type = BlockType.Url };
                                    }
                                }
                                else
                                {
                                    string nodeJsScriptPath = Data.Reflection.ConfigPath($"Static/Nodes/{file}.js");
                                    if (File.Exists(nodeJsScriptPath))
                                    {
                                        _ResBlockPage[new StringValue(path)] = new Block { Value = file, Type = BlockType.Nodejs };
                                    }
                                    else
                                    {

                                        var vfIndex = file.IndexOfAny(new char[] { ' ', '\t' });
                                        if (vfIndex > 0)
                                        {
                                            _ResBlockPage[new StringValue(path)] = new Block { Value = file.Substring(0, vfIndex), Content = file.Substring(vfIndex + 1).Trim(), Type = BlockType.Redirect };
                                        }
                                        else
                                        {
                                            _ResBlockPage[new StringValue(path)] = new Block { Content = file, Type = BlockType.Login };

                                        }
                                    }
                                }

                            }
                        }
                    }
                }

            }
        }
        void InitHost(String sConf)
        {
            var preHash = new Dictionary<String, HostConvert>();
            var domain = UMC.ITME.WebServlet.MainDomain;
            var union = UMC.ITME.WebServlet.DomainUnion;
            if (this.Domains.Length > 0)
            {
                // this.IsGotoMain = true;
                var url = this.Domains[0];
                var hostConvert = this.MainHost = new HostConvert();
                int sufx = 1;
                if (url.Contains('*'))
                {
                    IsUnion = true;
                    hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes($"-{this.Site.Root}{union}{domain}");
                    var l = new UMCUri(url.Replace("*.", ""));
                    hostConvert.Hosts[1] = System.Text.ASCIIEncoding.UTF8.GetBytes('.' + l.Host);
                    hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes('.' + l.UMCAuthority);
                    hostConvert.Hosts[3] = System.Text.ASCIIEncoding.UTF8.GetBytes(Uri.EscapeDataString('.' + l.UMCAuthority));

                    var pem = PrefixHost.Span.GetEnumerator();
                    while (pem.MoveNext())
                    {
                        var key = pem.Current.Item1.Span.UTF8();
                        preHash.Add(key, Convert(key, pem.Current.Item2));
                    }
                    var pem2 = this.ReferenceHost.Span.GetEnumerator();
                    while (pem2.MoveNext())
                    {
                        var key = pem2.Current.Item1.Span.UTF8();
                        preHash.Add(key, ReferenceHosts(key, pem2.Current.Item2));
                    }

                    Hex(hostConvert);
                    var suffixHost = new HostConvert();
                    suffixHost.Hosts[0] = this.MainHost.Hosts[0].AsSpan(sufx, this.MainHost.Hosts[0].Length - sufx).ToArray();// System.Text.ASCIIEncoding.UTF8.GetBytes(String.Format(".{0}{1}{2}", this.Site.Root, union, domain));

                    // suffixHost.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes(domain);
                    suffixHost.Hosts[1] = this.MainHost.Hosts[1].AsSpan(sufx, this.MainHost.Hosts[1].Length - sufx).ToArray();// System.Text.ASCIIEncoding.UTF8.GetBytes(String.Format(".{0}{1}{2}", this.Site.Root, union, domain));
                    suffixHost.Hosts[2] = this.MainHost.Hosts[2].AsSpan(sufx, this.MainHost.Hosts[2].Length - sufx).ToArray();// System.Text.ASCIIEncoding.UTF8.GetBytes(String.Format(".{0}{1}{2}", this.Site.Root, union, domain));
                    suffixHost.Hosts[3] = this.MainHost.Hosts[3].AsSpan(sufx, this.MainHost.Hosts[3].Length - sufx).ToArray();// System.Text.ASCIIEncoding.UTF8.GetBytes(String.Format(".{0}{1}{2}", this.Site.Root, union, domain));

                    Hex(suffixHost);

                    this.SuffixHost = suffixHost;

                }
                else
                {

                    if (String.IsNullOrEmpty(this.Site.Host) == false && this.Site.Host != "*")
                    {
                        url = url.Replace(new UMCUri(url).Host, this.Site.Host);
                    }
                    hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes($"{this.Site.Root}{union}{domain}");
                    var l = new UMCUri(url);
                    sufx = l.Host.IndexOf('.');
                    hostConvert.Hosts[1] = System.Text.ASCIIEncoding.UTF8.GetBytes(l.Host);
                    hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes(l.UMCAuthority);
                    hostConvert.Hosts[3] = System.Text.ASCIIEncoding.UTF8.GetBytes(Uri.EscapeDataString(l.UMCAuthority));

                    Hex(hostConvert);

                    this.SuffixHost = hostConvert;

                }
            }
            var hostPage = new Set<PageConfig<ReplaceSetting>>(PageConfig<ReplaceSetting>.comparer);
            // hostPage.TryGetValue
            if (String.IsNullOrEmpty(sConf) == false)
            {
                foreach (var k in sConf.Split('\n'))
                {
                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {

                        var nindex = -1;
                        for (int i = 0; i < v.Length; i++)
                        {
                            if (v[i] == ' ' || v[i] == '\t' || v[i] == ':')
                            {
                                nindex = i;
                                break;
                            }
                        }
                        var key = v;
                        if (nindex > -1)
                        {
                            var mv = v.Substring(nindex + 1).Split(',', ' ', '\t');
                            key = v.Substring(0, nindex).Trim();

                            var page = new PageConfig<ReplaceSetting>() { StartPath = StringValue.Empty, EndPath = StringValue.Empty };

                            var splitIndex = key.IndexOf('*');
                            switch (splitIndex)
                            {
                                case -1:
                                    page.StartPath = new StringValue(key);
                                    break;
                                case 0:
                                    if (key.Length > 1)
                                    {
                                        page.EndPath = new StringValue(key.Substring(1));
                                    }
                                    else
                                    {
                                        continue;
                                    }

                                    break;
                                default:
                                    if (splitIndex == key.Length - 1)
                                    {
                                        page.StartPath = new StringValue(key.Substring(0, key.Length - 1));
                                    }
                                    else
                                    {
                                        page.StartPath = new StringValue(key.Substring(0, splitIndex));
                                        page.EndPath = new StringValue(key.Substring(splitIndex + 1));

                                    }

                                    break;

                            }

                            if (hostPage.TryGetValue(page, out var _page) == false)
                            {
                                page.Value = new ReplaceSetting() { Model = HostReplaceModel.Replace };
                                _page = page;
                                hostPage.Put(page);

                            }
                            ReplaceSetting replaceSetting = _page.Value;//[key];
                            HostReplaceModel hostReplace = replaceSetting.Model;
                            var list = replaceSetting.Domains;
                            foreach (var p in preHash)
                            {
                                list.Put(p.Value);
                            }

                            foreach (var kv in mv)
                            {
                                var vk = kv.Trim();
                                if (String.IsNullOrEmpty(vk) == false)
                                {

                                    switch (vk)
                                    {
                                        case ".":
                                            if (this.IsUnion || union == '-')
                                            {

                                                var hostConvert = new HostConvert();
                                                if (union == '-')
                                                {
                                                    hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes(domain.Substring(domain.IndexOf('.') + 1));
                                                }
                                                else
                                                {
                                                    hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes(domain);
                                                }
                                                hostConvert.Hosts[1] = this.MainHost.Hosts[1].AsSpan(1, this.MainHost.Hosts[1].Length - 1).ToArray();// System.Text.ASCIIEncoding.UTF8.GetBytes(String.Format(".{0}{1}{2}", this.Site.Root, union, domain));
                                                hostConvert.Hosts[2] = this.MainHost.Hosts[2].AsSpan(1, this.MainHost.Hosts[2].Length - 1).ToArray();// System.Text.ASCIIEncoding.UTF8.GetBytes(String.Format(".{0}{1}{2}", this.Site.Root, union, domain));
                                                hostConvert.Hosts[3] = this.MainHost.Hosts[3].AsSpan(1, this.MainHost.Hosts[3].Length - 1).ToArray();// System.Text.ASCIIEncoding.UTF8.GetBytes(String.Format(".{0}{1}{2}", this.Site.Root, union, domain));
                                                Hex(hostConvert);
                                                list.Put(hostConvert);

                                            }
                                            break;
                                        default:
                                            var vIndex = vk.IndexOf(':');
                                            if (vIndex > 0)
                                            {
                                                var hostConvert = new HostConvert();

                                                var hMain = vk.Substring(0, vIndex).Trim();
                                                var proxy = vk.Substring(vIndex + 1).Trim();
                                                if (hMain.EndsWith("."))
                                                {
                                                    if (String.IsNullOrEmpty(proxy) == false && proxy.Contains('.') == false)
                                                    {
                                                        var vl = hMain.Replace('.', '-');
                                                        var sit = DataFactory.Instance().Site(proxy);
                                                        if (sit != null)
                                                        {
                                                            var doms = sit.Domain.Split(',', '\n');
                                                            foreach (var dName in doms)
                                                            {
                                                                var dName2 = dName.Trim();
                                                                var url = String.Empty;
                                                                if (String.IsNullOrEmpty(dName2) == false)
                                                                {
                                                                    var tIndex = dName2.IndexOf('~');
                                                                    if (tIndex > 0)
                                                                    {
                                                                        dName2 = dName2.Substring(0, tIndex).Trim();
                                                                    }

                                                                    if (dName2.EndsWith("]"))
                                                                    {
                                                                        var vin = dName2.LastIndexOf("[");
                                                                        if (vin > -1)
                                                                        {
                                                                            url = dName2.Substring(0, vin).TrimEnd(']', ' ').Trim();
                                                                        }
                                                                        else
                                                                        {
                                                                            url = dName2.Substring(0, vin).TrimEnd(']', ' ').Trim();
                                                                        }
                                                                        var sIndex = url.LastIndexOf('/');
                                                                        if (sIndex > 0)
                                                                        {

                                                                            url = url.Substring(0, sIndex);
                                                                        }
                                                                    }
                                                                    else if (v.IndexOf('@') == -1)
                                                                    {
                                                                        url = dName2;
                                                                        var sIndex = url.LastIndexOf('/');
                                                                        if (sIndex > 0)
                                                                        {
                                                                            url = url.Substring(0, sIndex);
                                                                        }

                                                                    }
                                                                }
                                                                if (String.IsNullOrEmpty(url) == false)
                                                                {
                                                                    if (url.Contains('*'))
                                                                    {
                                                                        hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes($"{vl}{sit.Root}{union}{domain}");
                                                                        var l = new UMCUri(url.Replace("*.", ""));
                                                                        hostConvert.Hosts[1] = System.Text.ASCIIEncoding.UTF8.GetBytes(hMain + l.Host);
                                                                        hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes(hMain + l.UMCAuthority);
                                                                        hostConvert.Hosts[3] = System.Text.ASCIIEncoding.UTF8.GetBytes(Uri.EscapeDataString(hMain + l.UMCAuthority));

                                                                        list.Put(hostConvert);
                                                                        break;
                                                                    }
                                                                }
                                                            }
                                                        }

                                                        break;
                                                    }
                                                }
                                                else if (String.Equals(hMain, "-"))
                                                {
                                                    hMain = $"{this.Site.Root}{union}{domain}";
                                                }
                                                hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes(hMain);

                                                if (String.IsNullOrEmpty(proxy) == false)
                                                {
                                                    var pIndex = proxy.IndexOf(':');
                                                    if (pIndex > 0)
                                                    {
                                                        hostConvert.Hosts[1] = System.Text.ASCIIEncoding.UTF8.GetBytes(proxy.Substring(0, pIndex));
                                                        hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes(proxy);

                                                    }
                                                    else
                                                    {
                                                        hostConvert.Hosts[1] =
                                                        hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes(proxy);

                                                    }
                                                    hostConvert.Hosts[3] = System.Text.ASCIIEncoding.UTF8.GetBytes(Uri.EscapeDataString(proxy));
                                                    Hex(hostConvert);
                                                    list.Put(hostConvert);
                                                }
                                            }
                                            else if (vk.EndsWith("."))
                                            {
                                                if (this.IsUnion)
                                                {
                                                    var vsrc = vk.Substring(0, vk.Length - 1);
                                                    var vv = vsrc.Replace('.', '-');
                                                    PrefixHost[new StringValue(vv)] = vsrc;
                                                    if (preHash.ContainsKey(vv) == false)
                                                    {
                                                        var hostConvert = Convert(vv, vsrc);
                                                        preHash[vv] = hostConvert;//Convert(vv, vsrc);

                                                        list.Put(hostConvert);
                                                    }
                                                }

                                            }
                                            else
                                            {
                                                var sit = DataFactory.Instance().Site(vk);
                                                if (sit != null)
                                                {
                                                    var doms = sit.Domain.Split(',', '\n');
                                                    foreach (var dName in doms)
                                                    {
                                                        var dName2 = dName.Trim();
                                                        var url = String.Empty;
                                                        if (String.IsNullOrEmpty(dName2) == false)
                                                        {
                                                            var tIndex = dName2.IndexOf('~');
                                                            if (tIndex > 0)
                                                            {
                                                                dName2 = dName2.Substring(0, tIndex).Trim();
                                                            }

                                                            if (dName2.EndsWith("]"))
                                                            {
                                                                var vin = dName2.LastIndexOf("[");
                                                                if (vin > -1)
                                                                {
                                                                    url = dName2.Substring(0, vin).TrimEnd(']', ' ').Trim();
                                                                }
                                                                else
                                                                {
                                                                    url = dName2.Substring(0, vin).TrimEnd(']', ' ').Trim();
                                                                }
                                                                var sIndex = url.LastIndexOf('/');
                                                                if (sIndex > 0)
                                                                {

                                                                    url = url.Substring(0, sIndex);
                                                                }
                                                            }
                                                            else if (v.IndexOf('@') == -1)
                                                            {
                                                                url = dName2;
                                                                var sIndex = url.LastIndexOf('/');
                                                                if (sIndex > 0)
                                                                {
                                                                    url = url.Substring(0, sIndex);
                                                                }

                                                            }
                                                        }
                                                        if (String.IsNullOrEmpty(url) == false && (url.StartsWith("https://") || url.StartsWith("http://")))
                                                        {
                                                            var hostConvert = new HostConvert();

                                                            if (url.Contains('*'))
                                                            {
                                                                hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes($"-{sit.Root}{union}{domain}");
                                                                var l = new UMCUri(url.Replace("*.", ""));
                                                                hostConvert.Hosts[1] = System.Text.ASCIIEncoding.UTF8.GetBytes('.' + l.Host);
                                                                hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes('.' + l.UMCAuthority);
                                                                hostConvert.Hosts[3] = System.Text.ASCIIEncoding.UTF8.GetBytes(Uri.EscapeDataString('.' + l.UMCAuthority));
                                                            }
                                                            else
                                                            {
                                                                if (String.IsNullOrEmpty(sit.Host) == false && sit.Host != "*")
                                                                {
                                                                    url = url.Replace(new UMCUri(url).Host, sit.Host);
                                                                }
                                                                hostConvert.Hosts[0] = System.Text.ASCIIEncoding.UTF8.GetBytes($"{sit.Root}{union}{domain}");
                                                                var l = new UMCUri(url);
                                                                hostConvert.Hosts[1] = System.Text.ASCIIEncoding.UTF8.GetBytes(l.Host);
                                                                hostConvert.Hosts[2] = System.Text.ASCIIEncoding.UTF8.GetBytes(l.UMCAuthority);
                                                                hostConvert.Hosts[3] = System.Text.ASCIIEncoding.UTF8.GetBytes(Uri.EscapeDataString(l.UMCAuthority));

                                                            }
                                                            Hex(hostConvert);
                                                            list.Put(hostConvert);
                                                            break;
                                                        }
                                                    }
                                                }
                                            }
                                            break;
                                        case "rp":
                                            hostReplace |= HostReplaceModel.Replace;
                                            break;
                                        case "rm":
                                            hostReplace |= HostReplaceModel.Replace;
                                            break;
                                        case "in":
                                            hostReplace |= HostReplaceModel.Input;
                                            break;
                                        case "none":
                                            hostReplace = HostReplaceModel.None;
                                            break;
                                    }
                                }
                            }
                            replaceSetting.Model = hostReplace;

                        }
                    }
                }
            }
            _HostPage = hostPage;
        }

        protected static readonly byte[] encodingTable =
        {
                (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
                (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
        };
        public static byte[] Hex(Span<byte> bytes)
        {
            var n = new byte[bytes.Length * 4];
            for (int i = 0; i < bytes.Length; i++)
            {
                n[4 * i] = (byte)'\\';
                n[4 * i + 1] = (byte)'x';

                int v = bytes[i];
                n[4 * i + 2] = encodingTable[v >> 4];
                n[4 * i + 3] = encodingTable[v & 0xf];
            }
            // n.Equals
            return n;
        }
        void Hex(HostConvert host)
        {
            for (int i = 0; i < host.Hosts.Length; i++)
            {
                host.Hex[i] = Hex(host.Hosts[i]);
            }
        }

        public static Guid MD5Key(params string[] keys)
        {
            var md5 = System.Security.Cryptography.MD5.Create();
            return new Guid(md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(String.Join(",", keys))));


        }
        void ConfigAllowPath(String sConf)
        {

            var saticPagePath = new Set<PageConfig<int>>(PageConfig<int>.comparer);
            Dictionary<String, Set<PageConfig<int>>> subs = new System.Collections.Generic.Dictionary<string, Set<PageConfig<int>>>();
            if (String.IsNullOrEmpty(sConf) == false)
            {

                foreach (var k in sConf.Split('\n'))
                {
                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {
                        var checPath = saticPagePath;
                        var vIndex = v.IndexOf(':');
                        if (vIndex > 0)
                        {
                            var key = v.Substring(0, vIndex);
                            if (subs.TryGetValue(key, out checPath) == false)
                            {

                                checPath = new Set<PageConfig<int>>(PageConfig<int>.comparer);//new EqualityComparer<int>());
                                subs.Add(key, checPath);
                            }
                            v = v.Substring(vIndex + 1).Trim();
                        }
                        if (String.IsNullOrEmpty(v))
                        {
                            continue;
                        }
                        var page = new PageConfig<int>() { StartPath = StringValue.Empty, EndPath = StringValue.Empty };

                        var splitIndex = v.IndexOf('*');
                        switch (splitIndex)
                        {
                            case -1:
                                page.StartPath = new StringValue(v);
                                break;
                            case 0:
                                if (v.Length > 1)
                                {
                                    page.EndPath = new StringValue(v.Substring(1));
                                }
                                else
                                {
                                    if (vIndex == -1)
                                    {
                                        this.AllowAllPath = true;
                                    }
                                    checPath.Clear();
                                    continue;
                                }

                                break;
                            default:
                                if (splitIndex == v.Length - 1)
                                {
                                    page.StartPath = new StringValue(v.Substring(0, v.Length - 1));
                                }
                                else
                                {
                                    page.StartPath = new StringValue(v.Substring(0, splitIndex));
                                    page.EndPath = new StringValue(v.Substring(splitIndex + 1));

                                }

                                break;

                        }
                        checPath.Put(page);


                    }
                }
            }
            this.AllowSubsPath = new Dictionary<string, PageConfig<int>[]>();
            var em = subs.GetEnumerator();
            while (em.MoveNext())
            {
                this.AllowSubsPath.Add(em.Current.Key, em.Current.Value.Span.ToArray());
            }
            this.AllowPath = saticPagePath.Span.ToArray();

            this.IsClose = this.Site.Flag < 0 || this.Domains.Length == 0;
        }
        // public bool IsCheckUserAgent
        // {
        //     get; private set;
        // }
        public bool IsDisabledApiSecure
        {

            get; private set;
        }
        public bool IsCheck()
        {
            if (this.IsClose == false)
            {
                if (UMC.Data.License.GetLicense($"Secure_{this.Site.Root}").ExpireTime < Utility.TimeSpan())
                {
                    IsDisabledApiSecure = true;
                    this.IsDisabledFingerprint = true;
                }
                if (this.IsForwardProxy == false)
                {
                    if (String.IsNullOrEmpty(this.Site.MarketKey) == false)
                    {
                        this.IsClose = UMC.Data.License.GetLicense(this.Site.MarketKey).ExpireTime < Utility.TimeSpan();

                        return this.IsClose;
                    }
                }
            }
            return false;
        }
        public static String[] Config(String sConf)
        {
            var saticPagePath = new HashSet<String>();
            if (String.IsNullOrEmpty(sConf) == false)
            {
                foreach (var k in sConf.Split(',', ' ', '\t', '\n'))
                {

                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {
                        saticPagePath.Add(v);
                    }
                }
            }
            return saticPagePath.ToArray();
        }

        void InitConfigImages(String sConf)
        {
            var saticPagePath = new Set<PageConfig<ImageConfig>>(PageConfig<ImageConfig>.comparer);

            if (String.IsNullOrEmpty(sConf) == false)
            {
                foreach (var k in sConf.Split('\n'))
                {
                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {
                        //new StringValue(v)

                        var conf = GetConf(String.Format("SITE_IMAGE_CONFIG_{0}{1}", this.Root, HttpProxy.MD5(v, String.Empty)).ToUpper());
                        if (conf.Count == 0)
                        {
                            continue;
                        }
                        var image = new ImageConfig();
                        image.Width = Utility.IntParse(conf["Width"] as string, 0);
                        image.Height = Utility.IntParse(conf["Height"] as string, 0);
                        image.Postion = Utility.IntParse(conf["Postion"] as string, 0);
                        image.ImageSize = Utility.IntParse(conf["ImageSize"] as string, 5);
                        image.Model = Utility.IntParse(conf["Model"] as string, 0);
                        image.Padding = Utility.IntParse(conf["Padding"] as string, 10);
                        image.Format = conf["Format"] as string ?? "Src";
                        image.FontColor = conf["FontColor"] as string;

                        image.WateRmark = conf["WateRmark"] as string;
                        image.WateRmarkText = conf["WateRmarkText"] as string;
                        image.Font = conf["Font"] as string;
                        image.ImagePath = conf["ImagePath"] as string;
                        var page = new PageConfig<ImageConfig>() { Value = image, StartPath = StringValue.Empty, EndPath = StringValue.Empty };

                        var splitIndex = v.IndexOf('*');
                        switch (splitIndex)
                        {
                            case -1:
                                page.StartPath = new StringValue(v);
                                break;
                            case 0:
                                if (v.Length > 1)
                                {
                                    page.EndPath = new StringValue(v.Substring(1));
                                }
                                else
                                {
                                    continue;
                                }

                                break;
                            default:
                                if (splitIndex == v.Length - 1)
                                {
                                    page.StartPath = new StringValue(v.Substring(0, v.Length - 1));
                                }
                                else
                                {
                                    page.StartPath = new StringValue(v.Substring(0, splitIndex));
                                    page.EndPath = new StringValue(v.Substring(splitIndex + 1));

                                }

                                break;

                        }
                        saticPagePath.Put(page);


                    }
                }



            }
            this.ImagesConf = saticPagePath.Span.ToArray();
        }

        PageConfig<StringValue>[] ConfigValue(String sConf)
        {
            var saticPagePath = new Set<PageConfig<StringValue>>((x, y) => x.Value.Span.SequenceCompareTo(y.Value.Span));

            if (String.IsNullOrEmpty(sConf) == false)
            {
                foreach (var k in sConf.Split('\n'))
                {
                    var v = k.Trim();
                    if (String.IsNullOrEmpty(v) == false && v.StartsWith("#") == false)
                    {
                        var page = new PageConfig<StringValue>() { Value = new StringValue(v), StartPath = StringValue.Empty, EndPath = StringValue.Empty };

                        var splitIndex = v.IndexOf('*');
                        switch (splitIndex)
                        {
                            case -1:
                                page.StartPath = new StringValue(v);
                                break;
                            case 0:
                                if (v.Length > 1)
                                {
                                    page.EndPath = new StringValue(v.Substring(1));
                                }
                                else
                                {
                                    continue;
                                }

                                break;
                            default:
                                if (splitIndex == v.Length - 1)
                                {
                                    page.StartPath = new StringValue(v.Substring(0, v.Length - 1));
                                }
                                else
                                {
                                    page.StartPath = new StringValue(v.Substring(0, splitIndex));
                                    page.EndPath = new StringValue(v.Substring(splitIndex + 1));

                                }

                                break;

                        }
                        saticPagePath.Put(page);


                    }
                }



            }
            return saticPagePath.Span.ToArray();
        }
        public String Home
        {
            get;
            private set;
        }
        public String Root
        {
            get; set;
        }

        public Entities.Site Site
        {
            get; private set;
        }

        public String[] Domains
        {
            get;
            private set;
        }
        public LogSetting LogConf
        {
            get;
            private set;
        }

        public PageConfig<int>[] AllowPath
        {
            get;
            private set;
        }
        public Dictionary<String, PageConfig<int>[]> AllowSubsPath
        {
            get;
            private set;
        }
        public Set<Tuple<StringValue, String, int>> LogoutPath
        {
            get
            {
                return _LogoutPath;
            }
        }

        Set<Tuple<StringValue, String, int>> _LogoutPath = new Set<Tuple<StringValue, string, int>>(Comparer<Tuple<StringValue, string, int>>.Create((x, y) =>
        {
            return x.Item1.Span.SequenceCompareTo(y.Item1.Span);
        }));
        Set<CookieSet.Cookie> _OutputCookies = new Set<CookieSet.Cookie>(Comparer<CookieSet.Cookie>.Create((x, y) =>
        {
            int t = x.Name.Span.SequenceCompareTo(y.Name.Span);

            if (t != 0)
            {
                return t;

            }
            return x.Domain.Span.SequenceCompareTo(y.Domain.Span);
        }));
        // Dictionary<String, CookieValues.Cookie> _OutputCookies = new Dictionary<string, StringValue>();
        // Dictionary<String, Set<CookieSet.Cookie>> _SubsOutputCookies = new Dictionary<string, Set<CookieSet.Cookie>>();

        public Set<CookieSet.Cookie> OutputCookies
        {
            get
            {
                return _OutputCookies;
            }
        }
        // public Dictionary<string, Set<CookieSet.Cookie>> SubCookies
        // {
        //     get
        //     {
        //         return _SubsOutputCookies;
        //     }
        // }
        public PageConfig<ImageConfig>[] ImagesConf
        {
            get;
            private set;
        }
        public PageConfig<StringValue>[] AppendJSConf
        {

            get;
            private set;
        }
        public PageConfig<StringValue>[] RedirectPath
        {
            get;
            private set;
        }
        public bool IsClose
        {

            get;
            private set;
        }
        public Span<HeaderConfItem> AppendCookies
        {
            get
            {
                return _AppendCookies.Span;
            }
        }
        Set<HeaderConfItem> _AppendCookies = new Set<HeaderConfItem>(Comparer<HeaderConfItem>.Create((x, y) =>
              {
                  var v = x.Prefix.Span.SequenceCompareTo(y.Prefix.Span);
                  if (v == 0)
                  {
                      return x.Name.Span.SequenceCompareTo(y.Name.Span);
                  }
                  return v;
              }));
        // Dictionary<StringValue, StringValue> _AppendCookies = new Dictionary<StringValue, StringValue>();
        public Span<HeaderConfItem> HeaderConf
        {
            get
            {
                return _HeaderConf.Span;
            }
        }
        Set<HeaderConfItem> _HeaderConf = new Set<HeaderConfItem>(Comparer<HeaderConfItem>.Create((x, y) =>
        {
            var v = x.Prefix.Span.SequenceCompareTo(y.Prefix.Span);
            if (v == 0)
            {
                return x.Name.Span.SequenceCompareTo(y.Name.Span);
            }
            return v;
        }));

        public PageConfig<int>[] StatusPage
        {
            get
            {
                return _StatusPage;
            }
        }
        public class PageConfig<T>
        {
            public StringValue StartPath;
            public StringValue EndPath;
            public T Value;
            public static IComparer<PageConfig<T>> comparer = Comparer<PageConfig<T>>.Create((x, y) =>
            {

                var l = x.StartPath.Span.SequenceCompareTo(y.StartPath.Span);
                if (l == 0)
                {
                    return x.EndPath.Span.SequenceCompareTo(y.EndPath.Span);
                }
                else
                {
                    return l;
                }
            });


        }
        PageConfig<int>[] _StatusPage;


        TestUrl[] _test;

        public TestUrl[] Test
        {

            get
            {
                return _test;
            }
        }
        Set<PageConfig<ReplaceSetting>> _HostPage;
        public Set<PageConfig<ReplaceSetting>> HostPage
        {
            get
            {
                return _HostPage;
            }
        }

        Set<StringValue, Block> _ResBlockPage = new Set<StringValue, Block>((x, y) => x.Span.IgnoreCaseCompareTo(y.Span));
        public Set<StringValue, Block> ResBlockPage
        {
            get
            {
                return _ResBlockPage;
            }
        }
        KeyValue[] _subSite;
        public KeyValue[] SubSite
        {
            get
            {
                return _subSite;

            }
        }
    }

    public class MimeConfig
    {
        public Uri Domain { get; set; }
        public String Name { get; set; }
        public String Caption { get; set; }
        public String RawUrl { get; set; }
        public StringValue ContentType { get; set; }
        Set<SiteConfig.HeaderConfItem> _HeaderConf = new Set<SiteConfig.HeaderConfItem>(Comparer<SiteConfig.HeaderConfItem>.Create((x, y) =>
      {
          var v = x.Prefix.Span.SequenceCompareTo(y.Prefix.Span);
          if (v == 0)
          {
              return x.Name.Span.SequenceCompareTo(y.Name.Span);
          }
          return v;
      }));
        // System.Collections.Generic.Dictionary<StringValue, String> _HeaderConf = new Dictionary<StringValue, String>();

        public Set<SiteConfig.HeaderConfItem> Headers => _HeaderConf;

        public String Content { get; set; }
        public HttpMethod Method { get; set; }
        public string DefautValue { get; set; }

        public bool IsRememberValue { get; set; }
        public String Script { get; set; }
        public StringValue Finish { get; set; }

        public int RetryCount { get; set; }


    }
    public class MimeFeildConfig : MimeConfig
    {
        public MimeConfig[] Feilds { get; set; }

    }
    public class LoginConfig : MimeFeildConfig
    {
        public String Callback { get; set; }

        public bool IsNotCookieClear { get; set; }
        public bool IsLoginHTML { get; set; }
        public MimeConfig LoginAfter { get; set; }
    }
    public class UpdateConfig : MimeFeildConfig
    {
        public String UpdateModel { get; set; }

    }
    public class CheckConfig : MimeFeildConfig
    {
        public bool IsNotLoginApi { get; set; }

    }
}
